home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / disk / cdrom / acdrom16.lha / AmiCDROM / device.c < prev    next >
C/C++ Source or Header  |  1993-11-21  |  34KB  |  1,215 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
  4.  * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  * 
  14.  * 21-Nov-93   fmu   - User programmable diskchange check interval.
  15.  *                   - Better support for ACTION_INHIBIT.
  16.  *                   - Handles filenames with ';'.
  17.  * 15-Nov-93   fmu   Missing return value for 'handler' inserted.
  18.  * 14-Nov-93   fmu   Added ACTION_USER packet for 'cdcontrol' program.
  19.  * 15-Oct-93   fmu   Adapted to new VOLUME structure.
  20.  * 10-Oct-93   fmu   - Creates volume node for 'no DOS' disks.
  21.  *             - Volume node now contains the correct volume
  22.  *               creation date.
  23.  * 09-Oct-93   fmu   - New format for mountlist startup field.
  24.  *             - SAS/C support.
  25.  *             - Debug process assembly tag adapted to small
  26.  *               memory model.
  27.  *             - Get_Startup moved to file devsupp.c.
  28.  * 03-Oct-93   fmu   - New buffering options 'S' and 'C'.
  29.  *                   - Fixed bug in cdlock.
  30.  *             - Fixed bug in ACTION_CURRENT_VOLUME.
  31.  * 27-Sep-93   fmu   Added ACTION_SAME_LOCK
  32.  * 25-Sep-93   fmu   - Send 'disk inserted' / 'disk removed' event via
  33.  *                     input.device if disk has been changed.
  34.  *                   - Corrected bug in ACTION_DISK_INFO.
  35.  * 24-Sep-93   fmu   - Added fast memory option 'F'.
  36.  *                   - Added ACTION_IS_FILESYSTEM.
  37.  *                   - Added 'write protected' error for write actions.
  38.  *                   - Added ACTION_CURRENT_VOLUME.
  39.  *                   - Unload handler code after ACTION_DIE.
  40.  *                   - Immediately terminate program if called from CLI.
  41.  *                   - Added library version number.
  42.  *                   - Set volume label to "Unnamed" for disks without name.
  43.  * 16-Sep-93   fmu   Added code to detect whether a lock stems from the
  44.  *                   current volume or from another volume which has
  45.  *                   been removed from the drive.
  46.  */
  47.  
  48. /*
  49.  *  Debugging routines are disabled by simply attempting to open the
  50.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  51.  *  attached to these names (you must be CD'd to TEST:).
  52.  *
  53.  *  See Documentation for a detailed discussion.
  54.  */
  55.  
  56. #include <stdlib.h>
  57. #include <string.h>
  58.  
  59. #if defined(_DCC) && !defined(REGISTERED)
  60. #define abs
  61. #endif
  62.  
  63. #include "device.h"
  64. #include "cdrom.h"
  65. #include "generic.h"
  66. #include "intui.h"
  67. #include "devsupp.h"
  68. #include "cdcontrol.h"
  69. #include "params.h"
  70.  
  71. /*
  72.  *  Since this code might be called several times in a row without being
  73.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  74.  *  for any global/static assignments that might be changed by running the
  75.  *  code.
  76.  */
  77.  
  78. PROC    *DosProc;     /* Our Process                        */
  79. DEVNODE *DosNode;     /* Our DOS node.. created by DOS for us            */
  80. DEVLIST *DevList;     /* Device List structure for our volume node       */
  81.  
  82. #if !defined(_DCC) || defined(REGISTERED)
  83. EXECLIB *SysBase;     /* EXEC library base                */
  84. #endif
  85. DOSLIB    *DOSBase;     /* DOS library base for debug process        */
  86. LIB    *UtilityBase; /* Utility library for miscellaneous tasks     */
  87.  
  88. CDROM   *g_cd;
  89. VOLUME  *g_volume;
  90. CDROM_OBJ *g_top_level_obj;
  91. char    *g_vol_name;
  92.  
  93. PORT *g_timer_mp;           /*  timer message port        */
  94. struct timerequest *g_timer_io; /*  timer i/o request        */
  95. ULONG g_timer_sigbit;
  96. ULONG g_dos_sigbit;
  97.  
  98. char    g_device[80];        /* SCSI device name */
  99. short    g_unit;            /* SCSI unit */
  100. short    g_use_rock_ridge;    /* Use Rock Ridge flag 'R' */
  101. short    g_map_to_lowercase;    /* Map to lower case flag 'L' */
  102. int     g_trackdisk;        /* Use trackdisk calls instead of SCSI-direct */
  103. int    g_fastmem;        /* Use fast memory for SCSI buffers */
  104. int    g_files_pending;    /* Number of open file handles */
  105.  
  106. int    g_std_buffers;        /* Number of buffers for standard SCSI access */
  107. int    g_file_buffers;        /* Number of buffers for contiguous reads */
  108.  
  109. t_bool    g_show_version_numbers; /* Show version numbers */
  110.  
  111. int    g_scan_interval;    /* Time between successive diskchange checks */
  112.  
  113. t_bool    g_disk_inserted;    /* Is a disk inserted? */
  114.  
  115. char    g_play_cdda_command[80];/* Command invoked if appicon is activated */
  116.  
  117. struct MsgPort *DosTask;
  118.  
  119. #ifndef NDEBUG
  120.             /*    DEBUGGING            */
  121. PORT *Dbport;        /*    owned by the debug process    */
  122. PORT *Dback;        /*    owned by the DOS device driver    */
  123. short DBDisable;
  124. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  125. #endif
  126.  
  127. void *dosalloc(ulong);
  128. void dosfree (ulong *);
  129. void btos(LONG, char *);
  130. void *NextNode (NODE *);
  131. void *GetHead (LIST *);
  132. LOCK *cdlock(CDROM_OBJ *, int);
  133. void cdunlock (LOCK *);
  134. CDROM_OBJ *getlockfile (LONG);
  135. char *typetostr (int);
  136. void returnpacket(struct DosPacket *);
  137. int packetsqueued (void);
  138. int Check_For_Volume_Name_Prefix (char *);
  139. void Fill_FileInfoBlock (FIB *, CDROM_INFO *, VOLUME *);
  140. void Mount (void);
  141. void Unmount (int);
  142. int Mount_Check (void);
  143. void Check_Disk (void);
  144. void Send_Timer_Request (void);
  145. void Cleanup_Timer_Device (void);
  146. int Open_Timer_Device (void);
  147. void Send_Event (int);
  148.  
  149. /*
  150.  *  Don't call the entry point main().  This way, if you make a mistake
  151.  *  with the compile options you'll get a link error.
  152.  */
  153.  
  154. #if defined(LATTICE)
  155. int __saveds handler (void)
  156. #elif defined(_DCC) && !defined(REGISTERED)
  157. int _main (void)
  158. #elif defined(_DCC) && defined(REGISTERED)
  159. __geta4 int handler (void)
  160. #else
  161. int handler (void)
  162. #endif
  163. {
  164.     register PACKET *packet;
  165.     register short   error;
  166.     MSG     *msg;
  167.     ubyte   notdone = 1;
  168.     char    buf[256];
  169.     void    *tmp;
  170.     ULONG   signals;
  171.     ubyte   playing = FALSE;
  172.  
  173.     /*
  174.      *    Initialize all global variables. SysBase MUST be initialized before
  175.      *  we can make Exec calls. The DOS library is opened for the debug
  176.      *  process only.
  177.      */
  178.  
  179. #if !defined(_DCC) || defined(REGISTERED)
  180.     SysBase = *(EXECLIB **) 4L;
  181. #endif
  182.     DosProc = (PROC *) FindTask(NULL);
  183.     if (DosProc->pr_CLI)
  184.       return RETURN_FAIL;
  185.     DOSBase = (DOSLIB *) OpenLibrary ((UBYTE *) "dos.library",37);
  186.     UtilityBase = (LIB *) OpenLibrary ((UBYTE *) "utility.library",37);
  187.  
  188.     BUG(DBDisable = 0;)                /*  Init. globals    */
  189.     BUG(Dbport = Dback = NULL;)
  190.     DevList = NULL;
  191.     g_disk_inserted = TRUE;
  192.     {
  193.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  194.     msg = GetMsg(&DosProc->pr_MsgPort);
  195.     packet = (PACKET *)msg->mn_Node.ln_Name;
  196.  
  197.     /*
  198.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  199.      *  instance of the device driver for every reference.    E.G. if
  200.      *  you were writing a CON device you would want this field to
  201.      *  be NULL.
  202.      */
  203.  
  204.         DosNode = BTOC(packet->dp_Arg3);
  205.  
  206.     Init_Intui ();
  207.  
  208.     if (UtilityBase && DOSBase && Get_Startup (packet->dp_Arg2)) {
  209.         /*
  210.          *    Set dn_Task field which tells DOS not to startup a new
  211.          *    process on every reference.
  212.          */
  213.  
  214.           DosNode->dn_Task = &DosProc->pr_MsgPort;
  215.         packet->dp_Res1 = DOS_TRUE;
  216.          packet->dp_Res2 = 0;
  217.         
  218.         DosTask = DosNode->dn_Task;
  219.  
  220.     } else {                /*    couldn't open dos.library   */
  221.         packet->dp_Res1 = DOS_FALSE;
  222.         returnpacket(packet);
  223.         return 0;                /*    exit process            */
  224.     }
  225.     returnpacket(packet);
  226.     }
  227.  
  228.     /*
  229.      *    Initialize debugging code
  230.      */
  231.  
  232.     BUG(dbinit();)
  233.  
  234.     BUG(dbprintf("%d std buffers, %d file buffers\n",
  235.              g_std_buffers, g_file_buffers);)
  236.  
  237.     g_timer_sigbit = 0;
  238.     if (g_scan_interval > 0) {
  239.       /* Initialize timer: */
  240.       if (Open_Timer_Device ())
  241.         Send_Timer_Request ();
  242.     }
  243.  
  244.     g_vol_name = dosalloc (128);
  245.  
  246.     /* Mount volume (if any disk is inserted): */
  247.     Mount ();
  248.  
  249.     g_dos_sigbit = 1L << DosProc->pr_MsgPort.mp_SigBit;
  250.  
  251.     g_files_pending = 0;
  252.  
  253.     /*
  254.      *    Here begins the endless loop, waiting for requests over our
  255.      *    message port and executing them.  Since requests are sent over
  256.      *    our message port, this precludes being able to call DOS functions
  257.      *    ourselves (that is why the debugging routines are a separate process)
  258.      */
  259.  
  260. top:
  261.     for (; notdone;) {
  262.     signals = Wait(g_dos_sigbit | g_timer_sigbit | g_app_sigbit);
  263.     if (signals & g_timer_sigbit) {
  264.       GetMsg (g_timer_mp);
  265.       Check_Disk ();
  266.       Send_Timer_Request ();
  267.     }
  268.     if (signals & g_app_sigbit) {
  269.       struct Message *msg;
  270.       while (msg = GetMsg (g_app_port)) {
  271.         ReplyMsg (msg);
  272.         if (g_play_cdda_command[0])
  273.           SystemTags ((UBYTE *) g_play_cdda_command,
  274.                   SYS_Input, Open ((UBYTE *) "NIL:", MODE_OLDFILE),
  275.                   SYS_Output, Open ((UBYTE *) "NIL:", MODE_NEWFILE),
  276.                   SYS_Asynch, TRUE,
  277.               TAG_END);
  278.         else {
  279.           if (playing)
  280.             Stop_Play_Audio (g_cd);
  281.           else
  282.             Start_Play_Audio (g_cd);
  283.           playing = !playing;
  284.         }
  285.       }
  286.     }
  287.     if (!(signals & g_dos_sigbit))
  288.       continue;
  289.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  290.         packet = (PACKET *)msg->mn_Node.ln_Name;
  291.         packet->dp_Res1 = DOS_TRUE;
  292.         packet->dp_Res2 = 0;
  293.         error = 0;
  294. #ifndef NDEBUG
  295.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  296.         packet->dp_Type,
  297.         packet->dp_Arg1, packet->dp_Arg2,
  298.         packet->dp_Arg3,
  299.         typetostr(packet->dp_Type)
  300.         );
  301. #endif
  302.  
  303.         if (packet->dp_Type != ACTION_DIE) {
  304.           if (DevList == NULL) {
  305.         packet->dp_Res1 = DOS_FALSE;
  306.         packet->dp_Res2 = (g_disk_inserted ? ERROR_NOT_A_DOS_DISK :
  307.                    ERROR_NO_DISK);
  308.         BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  309.         returnpacket(packet);
  310.         continue;            
  311.           }
  312.         }
  313.  
  314.         switch(packet->dp_Type) {
  315.         case ACTION_DIE:        /*    attempt to die?             */
  316.         notdone = 0;        /*    try to die                */
  317.         break;
  318.         case ACTION_USER:        /*  Mode,Par1,Par2            Bool    */
  319.             error = Handle_Control_Packet (packet->dp_Arg1,
  320.                            packet->dp_Arg2,
  321.                            packet->dp_Arg3);
  322.             break;
  323.         case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool    */
  324.         {
  325.             if (Mount_Check ()) {
  326.               CDROM_OBJ *obj;
  327.               CDROM_OBJ *parentdir = getlockfile(packet->dp_Arg2);
  328.               int       offs;
  329.  
  330.               if (parentdir->volume != g_volume) {
  331.                   /* old lock from another disk: */
  332.             error = ERROR_OBJECT_NOT_FOUND;
  333.             goto openbreak;
  334.               }
  335.               
  336.               btos(packet->dp_Arg3,buf);
  337.               BUG(dbprintf("'%s' ", buf);)
  338.               offs = Check_For_Volume_Name_Prefix (buf);
  339.               if (obj = Open_Object (parentdir, buf + offs)) {
  340.             if (obj->directory_f) {
  341.                 error = ERROR_OBJECT_WRONG_TYPE;
  342.                 goto openbreak;
  343.             }
  344.               } else {
  345.             if (iso_errno == ISOERR_ILLEGAL_NAME) {
  346.                 error = ERROR_INVALID_COMPONENT_NAME;
  347.                 goto openbreak;
  348.             } else if (iso_errno == ISOERR_NOT_FOUND)
  349.                   error = ERROR_OBJECT_NOT_FOUND;
  350.             else if (iso_errno == ISOERR_NO_MEMORY) {
  351.               error = ERROR_NO_FREE_STORE;
  352.               goto openbreak;
  353.             } else {
  354.               error = 333;
  355.               goto openbreak;
  356.             }
  357.               }
  358.               if (!error) {
  359.                 g_files_pending++;
  360.               ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long) obj;
  361.               }
  362.             } else
  363.               error = ERROR_NO_DISK;
  364.         }
  365.           openbreak:
  366.         break;
  367.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  368.         {
  369.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  370.             char      *ptr = (char *) packet->dp_Arg2;
  371.             long    length = packet->dp_Arg3;
  372.             int     actual;
  373.  
  374.             if (obj->volume != g_volume) {
  375.               /* old lock from another disk: */
  376.               error = ERROR_OBJECT_NOT_FOUND;
  377.               break;
  378.             }
  379.             actual = Read_From_File (obj, ptr, length);
  380.             packet->dp_Res1 = actual;
  381.         }
  382.         break;
  383.         case ACTION_END:        /*     FHArg1             Bool:TRUE  */
  384.         {
  385.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  386.  
  387.             Close_Object (obj);
  388.             g_files_pending--;
  389.         }
  390.         break;
  391.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  392.             {
  393.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  394.             long offset = packet->dp_Arg2;
  395.             int mode = packet->dp_Arg3;
  396.             
  397.             if (obj->volume != g_volume) {
  398.               /* old lock from another disk: */
  399.               error = ERROR_OBJECT_NOT_FOUND;
  400.               break;
  401.             }
  402.             packet->dp_Res1 = obj->pos;
  403.             if (!Seek_Position (obj, offset, mode)) {
  404.               error = ERROR_SEEK_ERROR;
  405.               packet->dp_Res1 = -1;
  406.             }
  407.         }
  408.         break;
  409.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  410.         {
  411.             FIB       *fib = BTOC (packet->dp_Arg2);
  412.             CDROM_OBJ *dir = getlockfile (packet->dp_Arg1);
  413.             CDROM_INFO info;
  414.  
  415.             if (dir->volume != g_volume) {
  416.               /* old lock from another disk: */
  417.               error = ERROR_OBJECT_NOT_FOUND;
  418.               break;
  419.             }
  420.             if (!dir->directory_f) {
  421.             error = ERROR_OBJECT_WRONG_TYPE;
  422.             break;
  423.             }
  424.             if (Examine_Next (dir, &info,
  425.                           (unsigned long *) &fib->fib_DiskKey)) {
  426.               error = 0;
  427.               Fill_FileInfoBlock (fib, &info, dir->volume);
  428.             } else {
  429.               error = ERROR_NO_MORE_ENTRIES;
  430.             }
  431.             break;
  432.         }
  433.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  434.         {
  435.             FIB *fib = BTOC (packet->dp_Arg2);
  436.                     CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  437.             CDROM_INFO info;
  438.  
  439.             if (obj->volume != g_volume) {
  440.               /* old lock from another disk: */
  441.               error = ERROR_OBJECT_NOT_FOUND;
  442.               break;
  443.             }
  444.             fib->fib_DiskKey = 0;
  445.             error = 0;
  446.             if (!CDROM_Info (obj, &info))
  447.               error = -1;
  448.             else
  449.               Fill_FileInfoBlock (fib, &info, obj->volume);
  450.         }
  451.         break;
  452.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  453.         tmp = BTOC(packet->dp_Arg2);
  454.         error = -1;
  455.         /*  fall through    */
  456.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  457.         {
  458.           if (Mount_Check ()) {
  459.             register INFODATA *id;
  460.  
  461.             (error) ? (id = tmp) : (id = BTOC (packet->dp_Arg1));
  462.             error = 0;
  463.             memset (id, 0, sizeof(*id));
  464.             id->id_DiskState = ID_WRITE_PROTECTED;
  465.             id->id_NumBlocks     = Volume_Size (g_volume);
  466.             id->id_NumBlocksUsed = id->id_NumBlocks;
  467.             id->id_BytesPerBlock = 2048;
  468.             id->id_DiskType = ID_DOS_DISK;
  469.             id->id_VolumeNode = (long) CTOB (DevList);
  470.             id->id_InUse = 0;
  471.           }
  472.         }
  473.         break;
  474.         case ACTION_IS_FILESYSTEM:   /*  -                      Bool */
  475.           packet->dp_Res1 = DOSTRUE;
  476.           break;
  477.         case ACTION_PARENT:     /*     Lock                ParentLock */
  478.             {
  479.           if (Mount_Check ()) {
  480.             if (packet->dp_Arg1) {
  481.               CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  482.               CDROM_OBJ *parent;
  483.           
  484.               if (obj->volume != g_volume) {
  485.                 /* old lock from another disk: */
  486.                 error = ERROR_OBJECT_NOT_FOUND;
  487.                 break;
  488.               }
  489.               if (Is_Top_Level_Object (obj)) {
  490.                 packet->dp_Res1 = packet->dp_Res2 = 0;
  491.               } else {
  492.                 parent = Find_Parent (obj);
  493.                 if (!parent) {
  494.                   if (iso_errno == ISOERR_NO_MEMORY)
  495.                     error = ERROR_NO_FREE_STORE;
  496.                   else
  497.                     error = ERROR_OBJECT_NOT_FOUND;
  498.                 } else {
  499.                   packet->dp_Res1 = (long)
  500.                 CTOB (cdlock (parent, ACCESS_READ));
  501.                 }
  502.               }
  503.             } else
  504.               error = ERROR_OBJECT_NOT_FOUND;
  505.           } else
  506.             error = ERROR_NO_DISK;
  507.         }
  508.         break;
  509.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  510.         {
  511.           if (Mount_Check ()) {
  512.             CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  513.                     CDROM_OBJ *obj;
  514.             int offs;
  515.  
  516.             if (parentdir->volume != g_volume) {
  517.               /* old lock from another disk: */
  518.               error = ERROR_OBJECT_NOT_FOUND;
  519.               break;
  520.             }
  521.             btos (packet->dp_Arg2, buf);
  522. #ifndef NDEBUG
  523.             dbprintf ("'%s' %ld ", buf, packet->dp_Arg3);
  524.             if (strcmp(buf,"debugoff") == 0)
  525.             DBDisable = 1;
  526.             if (strcmp(buf,"debugon") == 0)
  527.             DBDisable = 0;
  528. #endif
  529.  
  530.             offs = Check_For_Volume_Name_Prefix (buf);
  531.             if (buf[offs]==0) {
  532.               if (parentdir)
  533.                 obj = Clone_Object (parentdir);
  534.               else
  535.                 obj = Open_Top_Level_Directory (g_volume);
  536.             } else
  537.               obj = Open_Object (parentdir, buf + offs);
  538.             
  539.             if (obj) {
  540.               packet->dp_Res1 = (long) CTOB (cdlock (obj, packet->dp_Arg3));
  541.             } else {
  542.               if (iso_errno == ISOERR_SCSI_ERROR) {
  543.                 error = ERROR_OBJECT_NOT_FOUND;
  544.             Unmount (FALSE);
  545.               } else if (iso_errno == ISOERR_ILLEGAL_NAME)
  546.             error = ERROR_INVALID_COMPONENT_NAME;
  547.               else if (iso_errno == ISOERR_NOT_FOUND)
  548.             error = ERROR_OBJECT_NOT_FOUND;
  549.               else if (iso_errno == ISOERR_NO_MEMORY)
  550.                 error = ERROR_NO_FREE_STORE;
  551.               else
  552.                 error = 333;
  553.             }
  554.           } else
  555.             error = ERROR_NO_DISK;
  556.         }
  557.         break;
  558.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  559.             {
  560.           if (packet->dp_Arg1) {
  561.             CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  562.             CDROM_OBJ *new = Clone_Object (obj);
  563.           
  564.             if (!new)
  565.               error = ERROR_NO_FREE_STORE;
  566.             else
  567.               packet->dp_Res1 = (long) CTOB (cdlock (new, ACCESS_READ));
  568.           } else
  569.             packet->dp_Res1 = 0;
  570.         }
  571.         break;
  572.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  573.         if (packet->dp_Arg1);
  574.             cdunlock (BTOC(packet->dp_Arg1));
  575.         break;
  576.         case ACTION_CURRENT_VOLUME: /* -                        DevList    */
  577.             packet->dp_Res1 = (long) CTOB (DevList);
  578.             break;
  579.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  580.                 if (packet->dp_Arg1 == DOS_FALSE)
  581.           Check_Disk ();
  582.         break;
  583.         /*
  584.          *  FINDINPUT and FINDOUTPUT normally should return the
  585.          *  'write protected' error. If the field 'Name', however,
  586.          *  designates the root (e.g. CD0:), then the 'wrong type'
  587.          *  error should be returned. Otherwise, AmigaDOS would do
  588.          *  some funny things (such as saying 'Volume CD0: is write-
  589.          *  protected') if you try to mount the handler with the
  590.          *  field 'Mount' set to 1.
  591.          */
  592.         case ACTION_FINDOUTPUT: /*   Handle  Lock  Name         Bool       */
  593.         case ACTION_FINDUPDATE: /*   Handle  Lock  Name         Bool       */
  594.         {
  595.           int pos;
  596.           
  597.           btos(packet->dp_Arg3,buf);
  598.           BUG(dbprintf("'%s' ", buf);)
  599.           if ((pos = Check_For_Volume_Name_Prefix (buf)) &&
  600.               buf[pos] == 0)
  601.         error = ERROR_OBJECT_WRONG_TYPE;
  602.           else
  603.         error = ERROR_DISK_WRITE_PROTECTED;
  604.           break;
  605.         }
  606.         case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  607.         {
  608.           CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1),
  609.                     *obj2 = getlockfile(packet->dp_Arg2);
  610.  
  611.               if (Same_Objects (obj1, obj2))
  612.                 packet->dp_Res1 = DOSTRUE;
  613.           else
  614.                 packet->dp_Res1 = DOSFALSE;
  615.  
  616.           break;
  617.         }
  618.         case ACTION_RENAME_DISK:
  619.         case ACTION_WRITE:
  620.         case ACTION_SET_PROTECT:
  621.         case ACTION_DELETE_OBJECT:
  622.         case ACTION_RENAME_OBJECT:
  623.         case ACTION_CREATE_DIR:
  624.         case ACTION_SET_COMMENT:
  625.         case ACTION_SET_DATE:
  626.         case ACTION_SET_FILE_SIZE:
  627.               error = ERROR_DISK_WRITE_PROTECTED;
  628.               break;
  629.         /*
  630.          *    A few other packet types which we do not support
  631.          */
  632.         case ACTION_MORE_CACHE: /*     #BufsToAdd            Bool       */
  633.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  634.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  635.         case ACTION_SCREEN_MODE:/*     Bool(-1:RAW 0:CON)        OldState   */
  636.         default:
  637.         error = ERROR_ACTION_NOT_KNOWN;
  638.         break;
  639.         }
  640.         if (packet) {
  641.         if (error) {
  642.             BUG(dbprintf("ERR=%ld\n", error);)
  643.             packet->dp_Res1 = DOS_FALSE;
  644.             packet->dp_Res2 = error;
  645.         } else {
  646.             BUG(dbprintf("RES=%06lx\n", packet->dp_Res1));
  647.         }
  648.         returnpacket(packet);
  649.         }
  650.     }
  651.     }
  652.     BUG(dbprintf("Can we remove ourselves? ");)
  653.     Delay(100);        /*    I wanna even see the debug message! */
  654.     Forbid();
  655.     if (packetsqueued() || g_files_pending ||
  656.         (g_volume && g_volume->locks)) {
  657.     Permit();
  658.     BUG(dbprintf(" ..  not yet!\n");)
  659.     notdone = 1;
  660.     goto top;        /*  sorry... can't exit     */
  661.     } else
  662.     BUG(dbprintf(" ..  yes!\n");)
  663.  
  664.     /* remove timer device and any pending timer requests: */
  665.     if (g_timer_sigbit)
  666.       Cleanup_Timer_Device ();
  667.  
  668.     /* this is getting dangerous. We will unload our very own
  669.      * code via UnLoadSeg() and need to keep the system in
  670.      * Forbid() state in order to avoid getting the free memory
  671.      * reclaimed by other tasks. This means: *NO* Wait() after
  672.      * Unmount(TRUE) ist called!
  673.      */
  674.  
  675.     Unmount (TRUE);
  676.     
  677.     dosfree ((ulong *) g_vol_name);
  678.  
  679.     Cleanup_CDROM (g_cd);
  680.  
  681.     Close_Intui ();
  682.  
  683.     /*
  684.      *    Remove debug process, closedown, fall of the end of the world
  685.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  686.      *    had to RemTask(NULL) itself).
  687.      */
  688.  
  689.     BUG(dbuninit();)
  690.     if (UtilityBase)
  691.       CloseLibrary (UtilityBase);
  692.     if (DOSBase)
  693.       CloseLibrary ((struct Library *) DOSBase);
  694.     
  695.     return 0;
  696. }
  697.  
  698.  
  699. /*
  700.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  701.  *  can see by this and how the PACKET structure is extracted in the
  702.  *  GetMsg() of the main routine.
  703.  */
  704.  
  705. void returnpacket(struct DosPacket *packet)
  706. {
  707.     register struct Message *mess;
  708.     register struct MsgPort *replyport;
  709.  
  710.     replyport             = packet->dp_Port;
  711.     mess             = packet->dp_Link;
  712.     packet->dp_Port         = &DosProc->pr_MsgPort;
  713.     mess->mn_Node.ln_Name    = (char *)packet;
  714.     mess->mn_Node.ln_Succ    = NULL;
  715.     mess->mn_Node.ln_Pred    = NULL;
  716.     PutMsg(replyport, mess);
  717. }
  718.  
  719. /*
  720.  *  Are there any packets queued to our device?
  721.  */
  722.  
  723. int packetsqueued (void)
  724. {
  725.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  726.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  727. }
  728.  
  729. /*
  730.  *  DOS MEMORY ROUTINES
  731.  *
  732.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  733.  *  a FileLock structure, with additional private information after the
  734.  *  FileLock structure.  The longword before the beginning of the structure
  735.  *  must contain the length of structure + 4.
  736.  *
  737.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  738.  *  copy lock structures.  This means that if you want to be workbench
  739.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  740.  */
  741.  
  742. void *dosalloc(ulong bytes)
  743. {
  744.     register ulong *ptr;
  745.  
  746.     bytes += 4;
  747.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  748.     *ptr = bytes;
  749.     return(ptr+1);
  750. }
  751.  
  752. void dosfree (ulong *ptr)
  753. {
  754.     --ptr;
  755.     FreeMem(ptr, *ptr);
  756. }
  757.  
  758. /*
  759.  *  Convert a BSTR into a normal string.. copying the string into buf.
  760.  *  I use normal strings for internal storage, and convert back and forth
  761.  *  when required.
  762.  */
  763.  
  764. void btos(LONG bstr, char *buf)
  765. {
  766.     unsigned char *str = BTOC(bstr);
  767.     bmov((char *) str+1, buf, *str);
  768.     buf[*str] = 0;
  769. }
  770.  
  771. /*
  772.  *  Some EXEC list handling routines not found in the EXEC library.
  773.  */
  774.  
  775. void *NextNode (NODE *node)
  776. {
  777.     node = node->mln_Succ;
  778.     if (node->mln_Succ == NULL)
  779.     return(NULL);
  780.     return(node);
  781. }
  782.  
  783. void *GetHead (LIST *list)
  784. {
  785.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  786.     return(list->mlh_Head);
  787.     return(NULL);
  788. }
  789.  
  790. /*
  791.  *  The lock function.    The file has already been checked to see if it
  792.  *  is lockable given the mode.
  793.  */
  794.  
  795. LOCK *cdlock(CDROM_OBJ *cdfile, int mode)
  796. {
  797.   LOCK *lock = dosalloc (sizeof(LOCK));
  798.  
  799.   cdfile->volume->locks++;
  800.   lock->fl_Key = (long) cdfile;
  801.   lock->fl_Access = ACCESS_READ;
  802.   lock->fl_Task = &DosProc->pr_MsgPort;
  803.   lock->fl_Volume = (BPTR) CTOB (DevList);
  804.   return(lock);
  805. }
  806.  
  807. void cdunlock (LOCK *lock)
  808. {
  809.   CDROM_OBJ *obj = (CDROM_OBJ *) lock->fl_Key;
  810.  
  811.   if (--obj->volume->locks == 0 && !obj->volume->valid) {
  812.     Close_Volume (obj->volume);
  813.   }
  814.   Close_Object (obj);
  815.   dosfree ((ulong *) lock);                /* free lock        */
  816. }
  817.  
  818. /*
  819.  *  GETLOCKFILE(bptrlock)
  820.  *
  821.  *  Return the CDROM_OBJ (file or directory) associated with the
  822.  *  given lock, which is passed as a BPTR.
  823.  *
  824.  *  According to the DOS spec, the only way a NULL lock will ever be
  825.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  826.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  827.  *  the root directory of the CDROM.
  828.  */
  829.  
  830. CDROM_OBJ *getlockfile (LONG lock)
  831. {
  832.   LOCK *rl = BTOC (lock);
  833.  
  834.   if (rl)
  835.     return (CDROM_OBJ *) rl->fl_Key;
  836.   return g_top_level_obj;
  837. }
  838.  
  839. /*
  840.  * If p_pathname contains a ':' character, return the position of the first
  841.  * character after ':'
  842.  * Otherwise, return 0.
  843.  */
  844.  
  845. int Check_For_Volume_Name_Prefix (char *p_pathname)
  846. {
  847.   char *pos = strchr (p_pathname, ':');
  848.   
  849.   return pos ? (pos - p_pathname) + 1 : 0;
  850. }
  851.  
  852. /*
  853.  * Fills a FileInfoBlock with the information contained in the
  854.  * directory record of a CD-ROM directory or file.
  855.  */
  856.  
  857. void Fill_FileInfoBlock (FIB *p_fib, CDROM_INFO *p_info, VOLUME *p_volume)
  858. {
  859.   char *src = p_info->name;
  860.   char *dest = p_fib->fib_FileName+1;
  861.   int len = p_info->name_length;
  862.  
  863.   p_fib->fib_DirEntryType = p_info->directory_f ? 2 : -3;
  864.   
  865.   /* I don't know exactly why I have to set fib_EntryType, but other
  866.    * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
  867.    */
  868.    
  869.   p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  870.   
  871.   if (len == 1 && *src == ':') {
  872.     /* root of file system: */
  873.     p_fib->fib_DirEntryType = 2 /* was: 1 */;
  874.     /* file name == volume name: */
  875.     memcpy (p_fib->fib_FileName, g_vol_name, g_vol_name[0]+1);
  876.   } else {
  877.     /* copy file name: */
  878.     if (g_show_version_numbers) {
  879.       p_fib->fib_FileName[0] = len;
  880.       for (; len; len--)
  881.         *dest++ = *src++;
  882.     } else {
  883.       short i, real_len=len;
  884.       for (i=0; i<len; i++) {
  885.         if (*src == ';')
  886.       real_len = i;
  887.         *dest++ = *src++;
  888.       }
  889.       p_fib->fib_FileName[0] = real_len;
  890.     }
  891.  
  892.     if (g_map_to_lowercase && p_volume->protocol == PRO_ISO) {
  893.       /* convert ISO filename to lowercase: */
  894.       int i, len = p_fib->fib_FileName[0];
  895.       char *cp = p_fib->fib_FileName + 1;
  896.     
  897.       for (i=0; i<len; i++, cp++)
  898.         *cp = ToLower (*cp);
  899.     }
  900.   }
  901.   p_fib->fib_Protection = 0;
  902.   p_fib->fib_Size = p_info->file_length;
  903.   p_fib->fib_NumBlocks = p_info->file_length >> 11;
  904.   p_fib->fib_Comment[0] = 0;
  905.  
  906.   p_fib->fib_Date.ds_Days   = p_info->date / (24 * 60 * 60);
  907.   p_fib->fib_Date.ds_Minute = (p_info->date % (24 * 60 * 60)) / 60;
  908.   p_fib->fib_Date.ds_Tick   = (p_info->date % 60) * TICKS_PER_SECOND;
  909. }
  910.  
  911. /*
  912.  * Create Volume node and add to the device list. This will
  913.  * cause the WORKBENCH to recognize us as a disk. If we don't
  914.  * create a Volume node, Wb will not recognize us.
  915.  */
  916.  
  917. void Create_Volume_Node (LONG p_disk_type, ULONG p_volume_date)
  918. {
  919.   DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  920.   DEVLIST *dl;
  921.  
  922.   Forbid ();
  923.   DevList = dl = dosalloc(sizeof(DEVLIST));
  924.   dl->dl_Type = DLT_VOLUME;
  925.   dl->dl_Task = &DosProc->pr_MsgPort;
  926.   dl->dl_DiskType = p_disk_type;
  927.   dl->dl_Name = (BSTR) CTOB (g_vol_name);
  928.   dl->dl_VolumeDate.ds_Days = p_volume_date / (24 * 60 * 60);
  929.   dl->dl_VolumeDate.ds_Minute = (p_volume_date % (24 * 60 * 60)) / 60;
  930.   dl->dl_VolumeDate.ds_Tick = (p_volume_date % 60) * TICKS_PER_SECOND;
  931.   dl->dl_Next = di->di_DevInfo;
  932.   di->di_DevInfo = (long)CTOB(dl);
  933.   Permit ();
  934. }
  935.  
  936. /*
  937.  * Mount a volume.
  938.  */
  939.  
  940. void Mount (void)
  941. {
  942.   char buf[33];
  943.  
  944.   if (Has_Audio_Tracks (g_cd))
  945.     Show_CDDA_Icon ();
  946.  
  947.   g_volume = Open_Volume (g_cd, g_use_rock_ridge);
  948.   if (!g_volume) {
  949.     BUG(dbprintf ("!!! cannot open VOLUME !!!\n");)
  950. #if 0
  951.     strcpy (g_vol_name, "\9NoDosDisk");
  952.     Create_Volume_Node (ID_NOT_REALLY_DOS, 0);
  953.     Send_Event (TRUE);
  954. #endif
  955.     return;
  956.   } else {
  957.     g_disk_inserted = TRUE;
  958.     g_top_level_obj = Open_Top_Level_Directory (g_volume);
  959.     if (!g_top_level_obj) {
  960.       BUG(dbprintf ("!!! cannot open top level directory !!!\n");)
  961.       return;
  962.     }
  963.   }
  964.   
  965.   BUG(dbprintf ("***mounting*** ");)
  966.  
  967.   Volume_ID (g_volume, buf, sizeof (buf)-1);  
  968.   g_vol_name[0] = strlen (buf);
  969.   memcpy (g_vol_name+1, buf, strlen (buf));
  970.  
  971.   if (!(g_vol_name[0]))
  972.     memcpy (g_vol_name, "\7Unnamed", 8);
  973.  
  974.   /* AmigaDOS expects the BCPL string g_vol_name to be null-terminated: */
  975.   g_vol_name[g_vol_name[0]+1] = 0;
  976.  
  977.   Create_Volume_Node (ID_DOS_DISK, Volume_Creation_Date (g_volume));
  978.   Send_Event (TRUE);
  979. }
  980.  
  981. /*
  982.  *    Remove Volume entry.  Since DOS uses singly linked lists, we
  983.  *    must (ugg) search it manually to find the link before our
  984.  *    Volume entry.
  985.  */
  986.  
  987. void Unmount (int p_remove_device)
  988. {
  989.   DOSINFO *di;
  990.   DEVLIST *dl;
  991.   DEVNODE *dn;
  992.   void *dlp;
  993.  
  994.   Hide_CDDA_Icon ();
  995.  
  996.   Forbid ();
  997.   di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  998.  
  999.   if (DevList) {
  1000.     dlp = &di->di_DevInfo;
  1001.     for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
  1002.       dlp = &dl->dl_Next;
  1003.     if (dl == DevList) {
  1004.       *(BPTR *)dlp = dl->dl_Next;
  1005.       dosfree((ulong *) dl);
  1006.     } else {
  1007.       BUG(dbprintf("****PANIC: Unable to find volume node\n");)
  1008.     }
  1009.  
  1010.     if (DevList->dl_DiskType != ID_NOT_REALLY_DOS) {
  1011.       Close_Object (g_top_level_obj);
  1012.       if (g_volume->locks == 0)
  1013.         Close_Volume (g_volume);
  1014.       else {
  1015.         g_volume->valid = 0;
  1016.       }
  1017.     }
  1018.  
  1019.     DevList = NULL;
  1020.   }
  1021.  
  1022.   Send_Event (FALSE);
  1023.  
  1024.   g_volume = 0;
  1025.  
  1026.   /* when the handler code exits the corresponding device
  1027.    * node (e.g. "CD0") will be modified. The handler code
  1028.    * will be unloaded and the task entry will be set to
  1029.    * zero, so the next device access will reload and
  1030.    * restart the handler code.
  1031.    */
  1032.  
  1033.   if (p_remove_device) {
  1034.     di = BTOC (((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  1035.     dlp = &di->di_DevInfo;
  1036.     dn = BTOC (di->di_DevInfo);
  1037.  
  1038.     while (dn) {
  1039.       if (dn->dn_Task == DosTask) {
  1040.         BUG(dbprintf("got it! %b\n",dn->dn_Name);)
  1041.     if (TypeOfMem (BADDR (dn->dn_SegList))) {
  1042.       UnLoadSeg (dn->dn_SegList);
  1043.       dn->dn_SegList = 0;
  1044.     } else
  1045.       BUG(dbprintf("not a valid seglist\n");)
  1046.  
  1047.     dn->dn_Task = NULL;
  1048.  
  1049.         *(BPTR *) dlp = dn->dn_Next;
  1050.         dosfree ((ulong *) dn);
  1051.  
  1052.     break;
  1053.       }    else {
  1054.         dlp = &dn->dn_Next;
  1055.     dn = BTOC (dn->dn_Next);
  1056.       }
  1057.     }
  1058.   } else
  1059.     Permit ();
  1060. }
  1061.  
  1062. /*
  1063.  * Mount_Check returns 1 if a valid disk is inserted in the drive. A check is
  1064.  * only performed if previously the drive was empty.
  1065.  */
  1066.  
  1067. int Mount_Check (void)
  1068. {
  1069.   if (!g_disk_inserted) {
  1070.    /*
  1071.     * No disk was inserted up to now: we will check whether
  1072.     * a disk has been inserted by sending the test unit ready
  1073.     * command. We have to send the command twice because
  1074.     * the first SCSI command after inserting a new disk is
  1075.     * always rejected.
  1076.     */
  1077.     if (Test_Unit_Ready (g_cd) ||
  1078.         Test_Unit_Ready (g_cd)) {
  1079.       g_disk_inserted = TRUE;
  1080.       Mount ();
  1081.     } else {
  1082.       return 0;
  1083.     }
  1084.     if (DevList)
  1085.       return 1;
  1086.     else {
  1087.       /* Mount() did not succeed: */
  1088.       return 0;
  1089.     }
  1090.   }
  1091.   return 1;
  1092. }
  1093.  
  1094. /*
  1095.  *  Open timer device structures:
  1096.  */
  1097.  
  1098. int Open_Timer_Device (void)
  1099. {
  1100.   if (!(g_timer_mp = CreateMsgPort ())) {
  1101.     BUG(dbprintf ("cannot create timer message port!\n");)
  1102.     return 0;
  1103.   }
  1104.   if (!(g_timer_io = (struct timerequest *)
  1105.        CreateIORequest (g_timer_mp, sizeof (struct timerequest)))) {
  1106.     BUG(dbprintf ("cannot create timer i/o structure!\n");)
  1107.     DeleteMsgPort (g_timer_mp);
  1108.     return 0;
  1109.   }
  1110.   if (OpenDevice ((UBYTE *) TIMERNAME, UNIT_VBLANK,
  1111.             (struct IORequest *) g_timer_io, 0)) {
  1112.     BUG(dbprintf ("cannot open timer device!\n");)
  1113.     DeleteIORequest ((struct IORequest *) g_timer_io);
  1114.     DeleteMsgPort (g_timer_mp);
  1115.     return 0;
  1116.   }
  1117.   g_timer_sigbit = 1L << g_timer_mp->mp_SigBit;
  1118.   return 1;
  1119. }
  1120.  
  1121. /*
  1122.  *  Remove timer device structures:
  1123.  */
  1124.  
  1125. void Cleanup_Timer_Device (void)
  1126. {
  1127.   /* remove any pending requests: */
  1128.   if (!CheckIO ((struct IORequest *) g_timer_io))
  1129.     AbortIO ((struct IORequest *) g_timer_io);
  1130.   WaitIO ((struct IORequest *) g_timer_io);
  1131.   
  1132.   CloseDevice ((struct IORequest *) g_timer_io);
  1133.   DeleteIORequest ((struct IORequest *) g_timer_io);
  1134.   DeleteMsgPort (g_timer_mp);
  1135. }
  1136.  
  1137. /*
  1138.  *  Send timer request
  1139.  */
  1140.  
  1141. void Send_Timer_Request (void)
  1142. {
  1143.   g_timer_io->tr_node.io_Command = TR_ADDREQUEST;
  1144.   g_timer_io->tr_time.tv_secs = g_scan_interval;
  1145.   g_timer_io->tr_time.tv_micro = 0;
  1146.   SendIO ((struct IORequest *) g_timer_io);
  1147. }
  1148.  
  1149. /*
  1150.  *  Check whether the disk has been removed or inserted.
  1151.  */
  1152.  
  1153. void Check_Disk (void)
  1154. {
  1155.   BUG(dbprintf ("Checking Disk... ");)
  1156.   if (g_disk_inserted) {
  1157.     if (Test_Unit_Ready (g_cd)) {
  1158.       BUG(dbprintf ("no disk change  "));
  1159.     } else {
  1160.       g_disk_inserted = FALSE;
  1161.       BUG(dbprintf ("disk has been removed  ");)
  1162.       if (DevList)
  1163.         Unmount (FALSE);
  1164.       Hide_CDDA_Icon ();
  1165.     }
  1166.   }
  1167.   if (!g_disk_inserted) {
  1168.     if (Test_Unit_Ready (g_cd) ||
  1169.         Test_Unit_Ready (g_cd)) {
  1170.       g_disk_inserted = TRUE;
  1171.       BUG(dbprintf ("disk has been inserted");)
  1172.       Mount ();
  1173.     }
  1174.   }
  1175.   BUG(dbprintf ("\n");)
  1176. }
  1177.  
  1178. /* The following lines will generate a `disk inserted/removed' event, in order
  1179.  * to get Workbench to rescan the DosList and update the list of
  1180.  * volume icons.
  1181.  */
  1182.  
  1183. void Send_Event (int p_inserted)
  1184. {
  1185.   struct IOStdReq *InputRequest;/* OLSEN */
  1186.   struct MsgPort *InputPort;    /* OLSEN */
  1187.  
  1188.   if (InputPort = (struct MsgPort *) CreateMsgPort ()) {
  1189.     if (InputRequest = (struct IOStdReq *)
  1190.         CreateIORequest (InputPort, sizeof (struct IOStdReq))) {
  1191.       if (!OpenDevice ((UBYTE *) "input.device", 0,
  1192.                      (struct IORequest *) InputRequest, 0)) {
  1193.     static struct InputEvent InputEvent;
  1194.  
  1195.     memset (&InputEvent, 0, sizeof (struct InputEvent));
  1196.  
  1197.     InputEvent.ie_Class = p_inserted ? IECLASS_DISKINSERTED :
  1198.                        IECLASS_DISKREMOVED;
  1199.  
  1200.     InputRequest->io_Command = IND_WRITEEVENT;
  1201.     InputRequest->io_Data = &InputEvent;
  1202.     InputRequest->io_Length = sizeof (struct InputEvent);
  1203.  
  1204.     DoIO ((struct IORequest *) InputRequest);
  1205.  
  1206.     CloseDevice ((struct IORequest *) InputRequest);
  1207.       }
  1208.       DeleteIORequest (InputRequest);
  1209.     }
  1210.     DeleteMsgPort (InputPort);
  1211.   }
  1212. }
  1213.  
  1214.  
  1215.